import * as chai from "chai"
import * as mocha from "mocha"
import * as sinon from "sinon"
import sinonChai from "sinon-chai"
import { setTimeout } from "timers"
// import { setTimeout } from "timers/promises"
chai.use(sinonChai)
import Promise from "../src/promise"
const assert = chai.assert

describe("Promise", () => {
  it("is a class", () => {
    assert.isFunction(Promise)
    assert.isObject(Promise.prototype)
  })
  
  it("new Promise() 如果接收的不是一个函数就报错",()=>{
    assert.throw(()=>{
      // @ts-ignore
      new Promise()
    })
  })

  it("new Promise(fn) 会生成一个对象, 对象有 then 方法",()=>{
    const promise = new Promise(()=>{})
    assert.isFunction(promise.then)
  })

  it("new Promise(fn) 中的 fn 立即执行",()=>{
    let fn = sinon.fake()
    new Promise(fn)
    // @ts-ignore
    assert(fn.called)
  })

  it("new Promise(fn) 中的Fn 执行的时候接收 resolve和reject两个函数",(done)=>{
    new Promise((reslove:any,reject:any)=>{
      assert.isFunction(reslove)
      assert.isFunction(reject)
      done()
    })
  })

  it("Promise.then(success) 中的 success 会在 resolve 被调用的时候执行",(done)=>{
    let success = sinon.fake() 
    const promise = new Promise((resolve:any,reject:any)=>{
      assert.isFalse(success.called)
      resolve()
      // @ts-ignore
      setTimeout(()=>{
        assert.isTrue(success.called)
        done()
      },0)
    })
    // @ts-ignore
    promise.then(success)
  })

  it("Promise.then(success) 中的 fail 会在 reject 被调用的时候执行",(done)=>{
    let fail = sinon.fake() 
    const promise = new Promise((resolve:any,reject:any)=>{
      assert.isFalse(fail.called)
      reject()
      // @ts-ignore
      setTimeout(()=>{
        assert.isTrue(fail.called)
        done()
      },0)
    })
    // @ts-ignore
    promise.then(null,fail)
  })

  it("2.2.1",()=>{
    const promise = new Promise((resolve:any)=>{
      resolve()
    })
    promise.then(false,null)
    assert(1 === 1)
  })

  it("2.2.2",(done)=>{
    const succeed = sinon.fake()
    const promise = new Promise((resolve:any) =>{
      assert.isFalse(succeed.called)
      resolve(233)
      resolve(2333)
      // @ts-ignore
      setTimeout(()=>{
        assert(promise.state === "fulfilled")
        assert.isTrue(succeed.calledOnce)
        assert(succeed.calledWith(233))
        done()
      },0)
    })
    promise.then(succeed)
  })

  it("2.2.3",(done)=>{
    const fail = sinon.fake()
    const promise = new Promise((resolve:any,reject:any) =>{
      assert.isFalse(fail.called)
      reject(233)
      reject(2333)
      // @ts-ignore
      setTimeout(()=>{
        assert(promise.state === "rejected")
        assert.isTrue(fail.calledOnce)
        assert(fail.calledWith(233))
        done()
      },0)
    })
    promise.then(null,fail)
  })

  it("2.2.4 在我的diamante执行之前,不得调用 then 后面的俩函数",(done)=>{
    const succeed = sinon.fake()
    const promise = new Promise((resolve:any)=>{
      resolve()
    })
    promise.then(succeed)
    assert.isFalse(succeed.called)
    setTimeout(()=>{
      assert.isTrue(succeed.called);
      done();
    },0)
  })

  it("2.2.4 失败回调",(done)=>{
    const fn = sinon.fake()
    const promise = new Promise((resolve:any,reject:any)=>{
      reject()
    })
    promise.then(null,fn)
    assert.isFalse(fn.called)
    setTimeout(()=>{
      assert.isTrue(fn.called);
      done();
    },0)
  })

  it("2.2.5",(done)=>{
    const promise = new Promise((resolve:any)=>{
      resolve()
    })
    // @ts-ignore
    promise.then(function(){
      "use strict"
      // @ts-ignore
      assert(this === undefined)
      done()
    })
  })

  it("2.2.6 then可以在同一个promise里被多次调用",(done)=>{
    const promise = new Promise((resolve:any)=>{
      resolve()
    })
    const callbacks = [sinon.fake(),sinon.fake(),sinon.fake()]
    promise.then(callbacks[0])
    promise.then(callbacks[1])
    promise.then(callbacks[2])
    setTimeout(()=>{
      assert(callbacks[0].called)
      assert(callbacks[1].called)
      assert(callbacks[2].called)
      assert(callbacks[1].calledAfter(callbacks[0]))
      assert(callbacks[2].calledAfter(callbacks[1]))
      done()
    })
  })

  it("2.2.6.2 then可以在同一个promise里被多次调用",(done)=>{
    const promise = new Promise((resolve:any,reject:any)=>{
      reject()
    })
    const callbacks = [sinon.fake(),sinon.fake(),sinon.fake()]
    promise.then(null,callbacks[0])
    promise.then(null,callbacks[1])
    promise.then(null,callbacks[2])
    setTimeout(()=>{
      assert(callbacks[0].called)
      assert(callbacks[1].called)
      assert(callbacks[2].called)
      assert(callbacks[1].calledAfter(callbacks[0]))
      assert(callbacks[2].calledAfter(callbacks[1]))
      done()
    })
  })



})